package com.darknight.ftp.component.service.impl;

import com.darknight.ftp.component.service.UploadFileService;
import com.darknight.ftp.connection.FtpUserConnection;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;

/**
 * Created by DarKnight on 2017/5/24.
 */
@Service
public class UploadFileManager extends AbstractUploadFileManager implements UploadFileService {
    static private final String DEFAULT_FTP_ADDRESS = "localhost";

    static private String DEFAULT_FTP_PORT = "2121";

    static private String DEFAULT_ACCOUNT = "admin";

    static private String DEFAULT_PASSWORD = "admin";

    private Boolean defaultConfig;

    private String configuredFtpAddress;

    private String configuredFtpPort;

    private String configuredAccount;

    private String configuredPassword;

    private FtpUserConnection userConnect;

    private final FTPClient ftpClient;

    public UploadFileManager() {
//        this.userConnect = new FtpUserConnection("localhost", 2121, "admin", "admin");
        this.ftpClient = new FTPClient();
    }

    public UploadFileManager(FtpUserConnection userConnect) {
        this.userConnect = userConnect;
        this.ftpClient = new FTPClient();
    }

    public Boolean getDefaultConfig() {
        return defaultConfig;
    }

    @Value("${ftpserver.defaultConfig:true}")
    public void setDefaultConfig(Boolean defaultConfig) {
        this.defaultConfig = defaultConfig;
    }

    public String getConfiguredFtpAddress() {
        return configuredFtpAddress;
    }

    @Value("${ftpserver.ftpAddress:}")
    public void setConfiguredFtpAddress(String configuredFtpAddress) {
        this.configuredFtpAddress = configuredFtpAddress;
    }

    public String getConfiguredFtpPort() {
        return configuredFtpPort;
    }

    @Value("${ftpserver.ftpPort:}")
    public void setConfiguredFtpPort(String configuredFtpPort) {
        this.configuredFtpPort = configuredFtpPort;
    }

    public String getConfiguredAccount() {
        return configuredAccount;
    }

    @Value("${ftpserver.account:}")
    public void setConfiguredAccount(String configuredAccount) {
        this.configuredAccount = configuredAccount;
    }

    public String getConfiguredPassword() {
        return configuredPassword;
    }

    @Value("${ftpserver.password:}")
    public void setConfiguredPassword(String configuredPassword) {
        this.configuredPassword = configuredPassword;
    }

    public FtpUserConnection getUserConnect() {
        return userConnect;
    }

    public void setUserConnect(FtpUserConnection userConnect) {
        this.userConnect = userConnect;
    }

    private String getFtpAddress() {
        String ftpAddress;

        if(StringUtils.isNotBlank(configuredFtpAddress)) {
            ftpAddress = configuredFtpAddress;
        }else {
            if(defaultConfig) {
                ftpAddress = DEFAULT_FTP_ADDRESS;
            }else {
                ftpAddress = null;
            }
        }

        return ftpAddress;
    }

    private Integer getFtpPort() {
        Integer ftpPort;

        if(StringUtils.isNumeric(configuredFtpPort)) {
            ftpPort = Integer.valueOf(configuredFtpPort);
        }else {
            if(defaultConfig) {
                ftpPort = Integer.valueOf(DEFAULT_FTP_PORT);
            }else {
                ftpPort = null;
            }
        }

        return ftpPort;
    }

    private String getAccount() {
        String account;

        if(StringUtils.isNotBlank(configuredAccount)) {
            account = configuredAccount;
        }else {
            if(defaultConfig) {
                account = DEFAULT_ACCOUNT;
            }else {
                account = null;
            }
        }

        return account;
    }

    private String getPassword() {
        String password;

        if(StringUtils.isBlank(configuredPassword)) {
            if(defaultConfig) {
                password = DEFAULT_PASSWORD;
            }else {
                password = configuredPassword;
            }
        }else {
            password = configuredPassword;
        }

        return password;
    }

    /**
     * 判断FTP客户端是否登录成功
     * @return
     * @throws IOException
     */
    private boolean isLoginSuccess() throws IOException {
        int reply = ftpClient.getReplyCode();

        if(FTPReply.isPositiveCompletion(reply)) {
            System.out.println("FTP服务器登录成功");
            return true;
        }
        System.out.println("FTP服务器登录失败");
        return false;
    }

//    public boolean downloadFile(String storeFilePath, String remoteFileName, OutputStream outputStream) throws IOException {
//        Assert.hasText(storeFilePath, "待下载文件目录为空");
//        Assert.hasText(remoteFileName, "待下载文件名为空");
//        Assert.notNull(outputStream, "下载文件输出流为空");
//        boolean optSuccess = false;
//
//        connectFtpServer();
//        //如果采用默认端口，可以使用ftp.connect(url)的方式直接连接FTP服务器
//        loginFtpServer();
//        if (!isLoginSuccess()) {
//            ftpClient.disconnect();
//
//            return optSuccess;
//        }
//        if(hasStoreFilePath(storeFilePath)) {
//            boolean reachStoreFilePathResult = reachStoreFilePath(storeFilePath);
//            Assert.isTrue(reachStoreFilePathResult, "无法进入待下载文件目录");
//        }
//        ftpClient.setControlEncoding("UTF-8");
//        ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
////        String remoteFilePath = StringUtils.join(storeFilePath, "/", remoteFileName);
//        boolean retrieveResult = ftpClient.retrieveFile(remoteFileName, outputStream);
//        Assert.isTrue(retrieveResult, "文件无法下载");
////        outputStream.close();
//
//        ftpClient.logout();
//        if (ftpClient.isConnected()) {
//            ftpClient.disconnect();
//        }
//        optSuccess = true;
//
//        return optSuccess;
//    }
//
//    public boolean downloadFile(String storeFilePath, String remoteFileName, String downloadFilePath) throws IOException {
//        Assert.hasText(storeFilePath, "待下载文件目录为空");
//        Assert.hasText(remoteFileName, "待下载文件名为空");
//        Assert.hasText(downloadFilePath, "下载文件保存路径为空");
//
//        File targetFile = new File(downloadFilePath);
//        FileOutputStream outputStream = FileUtils.openOutputStream(targetFile);
//        boolean optSuccess = downloadFile(storeFilePath, remoteFileName, outputStream);
//        outputStream.close();
//
//        return optSuccess;
//    }




    @Override
    public FtpUserConnection getConnection(String ftpHostName, Integer ftpPort) throws IOException {
        Assert.notNull(ftpHostName, "FTP访问路径不能为空");
        Assert.notNull(ftpPort, "FTP访问端口不能为空");

        if(userConnect == null) {
            userConnect = new FtpUserConnection(ftpHostName, ftpPort);

            return userConnect;
        }else {
            if(StringUtils.equalsIgnoreCase(ftpHostName, userConnect.getFtpHostName())) {
                if(ftpPort != null && userConnect.getFtpPort() != null && ftpPort.equals(userConnect.getFtpPort())) {

                    return userConnect;
                }
            }

            return new FtpUserConnection(ftpHostName, ftpPort);
        }
    }

    @Override
    public FtpUserConnection getConnectedConnection(String ftpHostName, Integer ftpPort) throws IOException {
        FtpUserConnection connection = getConnection(ftpHostName, ftpPort);

        // 连接FTP服务器
        connection.connectFtpServer();

        return connection;
    }

    public void releaseConnection(FtpUserConnection connection) throws IOException {
        Assert.notNull(connection, "FTP连接为空，无可释放连接");

        connection.disconnect();
    }

    @Override
    public void returnConnection(FtpUserConnection connection) {
        Assert.notNull(connection, "FTP连接为空，无可释放连接");

        try {
            releaseConnection(connection);
        } catch (IOException e) {
            e.printStackTrace();

            // 将IO异常降级为Runtime异常，返回相应信息，以便进行后续提示和操作
            throw new RuntimeException(e.getMessage());
        }
    }
}
